﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ObjectDirectory;
using Numbers;

namespace System8Equations
{
    /// <summary>
    /// Nice interface for dealing with S8 eqn series accumulation.
    /// </summary>
    public class S8EqnSeriesAccumulator
    {
        /// <summary>
        /// Private S8 variables we need to be using
        /// </summary>
        private S8Equations _s8 = new S8Equations();

        /// <summary>
        /// The object path manager.
        /// </summary>
        private ObjectPathManager _mgr = new ObjectPathManager();

        /// <summary>
        /// The guy that actually watches the eqns.
        /// </summary>
        private EqnSeriesAccumulator _seriesWatcher = new EqnSeriesAccumulator();

        /// <summary>
        /// Get/Set the values for the S8 equations. Set only copies the
        /// values, it doesn't remember the whole object.
        /// </summary>
        public S8Equations S8
        {
            get { return _s8; }
            set { _s8.Copy(value); }
        }

        /// <summary>
        /// Add a variable that we are going to want to watch
        /// </summary>
        /// <param name="path">String path to the variable from the S8 guy</param>
        /// <returns></returns>
        public EqnSeriesAccumulator.ColumnReference Watch(string path)
        {
            Value v = _mgr.FindObjectFromPath(S8, path) as Value;
            return _seriesWatcher.Watch(() => v.Val);
        }

        /// <summary>
        /// Set the given value (relative by path from S8) to the value from SetAValue on each iteration.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="setAValueOncePerIteration"></param>
        public void SetOnIteration(string path, Func<double> setAValueOncePerIteration)
        {
            Value v = _mgr.FindObjectFromPath(S8, path) as Value;
            _seriesWatcher.SetOnIteration(() => v.Val = setAValueOncePerIteration());
        }

        /// <summary>
        /// Run the loop some number of times
        /// </summary>
        /// <param name="iterations"></param>
        public void Loop(int iterations)
        {
            _seriesWatcher.Loop(iterations);
        }

        /// <summary>
        /// Return the doubles associated with a particular readout.
        /// </summary>
        /// <param name="wref"></param>
        /// <returns></returns>
        public double[] GetValueList(EqnSeriesAccumulator.ColumnReference wref)
        {
            return _seriesWatcher.GetValueList(wref);
        }

        /// <summary>
        /// Use one of the iternator setupss to watch a variable.
        /// Make sure to update it with teh value we are going to run
        /// just in case it has changed and it needs to update itself.
        /// </summary>
        /// <param name="s8Var"></param>
        public void SetOnIteration(S8Variable s8Var)
        {
            Value v = _mgr.FindObjectFromPath(S8, s8Var.Path) as Value;
            if (v == null)
            {
                throw new InvalidOperationException("Could not find the path '" + s8Var.Path + "'.");
            }

            s8Var.Update(v.Val);

            var itr = s8Var.GetEnumerator();
            _seriesWatcher.SetOnIteration(() =>
            {
                itr.MoveNext();
                v.Val = itr.Current;
            });
        }
    }
}
